package com.powernode.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.powernode.constant.BusinessEnum;
import com.powernode.constant.HttpConstants;
import com.powernode.constant.ResourceConstants;
import com.powernode.filter.TokenAnalysisFilter;
import com.powernode.model.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.io.PrintWriter;

/**
 * @Description: Spring Security 安全框架的资源服务器配置类
 * @Author: Tong Ziyu
 * @Date: 2024/11/4 21:48
 */
@Configuration
// 开启方法前置权限判断
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private TokenAnalysisFilter tokenAnalysisFilter;


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 关闭跨站请求伪造
        http.cors().disable();

        // 关闭跨域请求
        http.csrf().disable();

        // 关闭session使用策略
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);


        // 添加一个前置过滤器
        // 这个过滤器的作用就是将请求头中的token取出来,从redis中取出来,获取到用户信息,封装成security认识的对象
        http.addFilterBefore(tokenAnalysisFilter, UsernamePasswordAuthenticationFilter.class);

        // 配置处理携带token但权限不足的请求
        http.exceptionHandling()
                // 处理没有携带token的请求
                .authenticationEntryPoint(authenticationEntryPoint())
                // 处理携带token但是权限不足的请求
                .accessDeniedHandler(null);

        // 配置其他请求
        // 除了需要放行的请求,其余的请求都需要身份的认证
        http.authorizeRequests()
                .antMatchers(ResourceConstants.RESOURCE_ALLOW_URLS)
                .permitAll()
                .anyRequest()
                .authenticated();
    }

    /**
     * 没有携带token
     *
     * @return
     */
    @Bean
    public AuthenticationEntryPoint authenticationEntryPoint() {
        return (request, response, authException) -> {
            // 设置响应格式
            response.setContentType(HttpConstants.CONTENT_TYPE);
            response.setCharacterEncoding(HttpConstants.CHARACTER_ENCODING);

            // 拿到writer
            PrintWriter writer = response.getWriter();
            Result<Object> fail = Result.fail(BusinessEnum.UN_AUTHORIZATION);
            // 转成Json
            ObjectMapper objectMapper = new ObjectMapper();
            String responseJson = objectMapper.writeValueAsString(fail);

            writer.write(responseJson);

            writer.flush();

            writer.close();
        };
    }

    /**
     * 访问拒绝
     *
     * @return
     */
    @Bean
    public AccessDeniedHandler accessDeniedHandler() {
        return (request, response, accessDeniedException) -> {
            response.setContentType(HttpConstants.CONTENT_TYPE);
            response.setCharacterEncoding(HttpConstants.CHARACTER_ENCODING);

            PrintWriter writer = response.getWriter();

            Result<Object> fail = Result.fail(BusinessEnum.ACCESS_DENY);

            ObjectMapper objectMapper = new ObjectMapper();

            String responseJson = objectMapper.writeValueAsString(fail);

            writer.write(responseJson);

            writer.flush();

            writer.close();
        };
    }
}
